package com.example.wastewater.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.wastewater.common.convention.exception.ServiceException;
import com.example.wastewater.dao.entity.WastewaterDO;
import com.example.wastewater.dao.entity.WaterDataPreditDO;
import com.example.wastewater.dao.mapper.WastewaterMapper;
import com.example.wastewater.dao.mapper.WaterDataPreditMapper;
import com.example.wastewater.dto.resp.WwPredictOneRespDTO;
import com.example.wastewater.dto.resp.WwRandomOneNoBODRespDTO;
import com.example.wastewater.service.IWasteWaterService;
import com.zhipu.oapi.ClientV4;
import com.zhipu.oapi.Constants;
import com.zhipu.oapi.service.v4.model.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;


@Service
@RequiredArgsConstructor
@Slf4j
public class WasteWaterServiceImpl extends ServiceImpl<WastewaterMapper, WastewaterDO> implements IWasteWaterService {
    private final WastewaterMapper wastewaterMapper;
    private final WaterDataPreditMapper waterDataPreditMapper;
    private final StringRedisTemplate stringRedisTemplate;
    private static final String API_SECRET_KEY = "d59fbba97971fef02b060a5103665b14.u4IqRbATGji1zu9a";
    private static final String WATER_DATA_REPORT = "wastewater:water-data:report:%s";
    private static final String WATER_DATA_REPORT_TASK = "wastewater:water-data:report-task:%s";


    private static final ClientV4 client = new ClientV4.Builder(API_SECRET_KEY)
            .enableTokenCache()
            .networkConfig(300, 100, 100, 100, TimeUnit.SECONDS)
            .connectionPool(new okhttp3.ConnectionPool(8, 1, TimeUnit.SECONDS))
            .build();

    // 请自定义自己的业务id
    private static final String requestIdTemplate = "mycompany-%d";

    @Override
    public WwRandomOneNoBODRespDTO getRandomOneNoBOD() {
        WastewaterDO wastewaterDO = wastewaterMapper.selectRandomData();
        WwRandomOneNoBODRespDTO wwRandomOneNoBODRespDTO = BeanUtil.copyProperties(wastewaterDO, WwRandomOneNoBODRespDTO.class);
        return wwRandomOneNoBODRespDTO;
    }

//    @Override
//    public WwOneRespDTP getOne(Long id) {
//        if(id == null || id < 0){
//            throw new ClientException("id不合法");
//        }
//
//        String waterData = stringRedisTemplate.opsForValue().get(WATER_DATA_KEY + id);
//        WastewaterDO wastewaterDO = null;
//        if(StrUtil.isBlank(waterData)){
//            wastewaterDO = lambdaQuery()
//                    .eq(WastewaterDO::getId, id)
//                    .eq(WastewaterDO::getDelFlag, 0)
//                    .one();
//            if(wastewaterDO == null){
//                throw new ClientException("数据不存在");
//            }
//            stringRedisTemplate.opsForValue().set(WATER_DATA_KEY + id, JSONUtil.toJsonStr(wastewaterDO), 3, TimeUnit.HOURS);
//        }else {
//            wastewaterDO = JSONUtil.toBean(waterData, WastewaterDO.class);
//        }
//
//        return BeanUtil.copyProperties(wastewaterDO, WwOneRespDTP.class);
//    }


    @Override
    public List<WwPredictOneRespDTO> getPreditData(Integer count) {
        List<WaterDataPreditDO> waterDataPreditDOS = waterDataPreditMapper.selectNewData(count);
        if (CollUtil.isEmpty(waterDataPreditDOS)) {
            log.warn("预测列表为空");
        }
        List<WwPredictOneRespDTO> respDTOList = new ArrayList<>();
        for (WaterDataPreditDO waterDataPreditDO : waterDataPreditDOS) {
            WastewaterDO wastewaterDO = baseMapper.selectById(waterDataPreditDO.getOrginId());
            if (wastewaterDO == null) {
                log.error("废水数据不存在");
            }
            WwPredictOneRespDTO wwPredictOneRespDTO = BeanUtil.copyProperties(wastewaterDO, WwPredictOneRespDTO.class);
            wwPredictOneRespDTO.setBiologicalOxygenDemandPredit(waterDataPreditDO.getBiologicalOxygenDemandPredit());
            wwPredictOneRespDTO.setUpdatedAt(waterDataPreditDO.getUpdatedAt());
            respDTOList.add(wwPredictOneRespDTO);
        }

        CompletableFuture.runAsync(() -> {
            Long id = respDTOList.get(0).getId();
            stringRedisTemplate.opsForValue().set(String.format(WATER_DATA_REPORT_TASK, id), runAsyncTask(id), 1, TimeUnit.MINUTES);
        });
        return respDTOList;
    }

    @Override
    public String getReport(Long id){
        String reportKey = String.format(WATER_DATA_REPORT, id);
        String resp = stringRedisTemplate.opsForValue().get(reportKey);
        if (StrUtil.isNotBlank(resp)) {
            return resp;
        }
        String taskId = stringRedisTemplate.opsForValue().get(String.format(WATER_DATA_REPORT_TASK, id));
        if (StrUtil.isNotBlank(taskId)) {
            return queryResult(id.toString(), taskId);
        } else {
            runAsyncTask(id);
            throw new ServiceException("系统繁忙，请稍后再试");
        }
    }

    private String runAsyncTask(Long id) {
        String taskId = stringRedisTemplate.opsForValue().get(String.format(WATER_DATA_REPORT_TASK, id));
        if (StrUtil.isNotBlank(taskId)) {
            return taskId;
        }
        WastewaterDO wastewaterDO = baseMapper.selectById(id);
        Integer BOD = waterDataPreditMapper.selectBODbyOrginId(id);
        List<ChatMessage> messages = getChatMessages(wastewaterDO, BOD);
        String requestId = String.format(requestIdTemplate, System.currentTimeMillis());

        ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
                .model(Constants.ModelChatGLM4)
                .stream(Boolean.FALSE)
                .invokeMethod(Constants.invokeMethodAsync)
                .messages(messages)
                .requestId(requestId)
                .maxTokens(3000)
                .build();
        try {
            ModelApiResponse invokeModelApiResp = client.invokeModelApi(chatCompletionRequest);
            taskId = invokeModelApiResp.getData().getId();
            stringRedisTemplate.opsForValue().set(String.format(WATER_DATA_REPORT_TASK, id), taskId);
            return taskId;
        } catch (Exception e) {
            throw new ServiceException("大模型调用失败");
        }
    }

    @NotNull
    private static List<ChatMessage> getChatMessages(WastewaterDO wastewaterDO, Integer BOD) {
        List<ChatMessage> messages = new ArrayList<>();
        ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(),
                "你是一个水质检测员，接下来给出你水质相关参数，请你简要给出报告内容，报告格式为：指标1：值（单位)：当前水质异常指标为：可能的因素为：建议方案为：" +
                        "averageOutflow:" + wastewaterDO.getAverageOutflow() + "/n" +
                        "averageInflow:" + wastewaterDO.getAverageInflow() + "/n" +
                        "energyConsumption:" + wastewaterDO.getEnergyConsumption() + "/n" +
                        "ammonia:" + wastewaterDO.getAmmonia() + "/n" +
                        "biologicalOxygenDemand:" + BOD + "(注意：这是根据其他值预测的bod，因为这个参数检测时间比其他远远要长)" + "/n" +
                        "chemicalOxygenDemand:" + wastewaterDO.getChemicalOxygenDemand() + "/n" +
                        "totalNitrogen:" + wastewaterDO.getTotalNitrogen() + "/n" +
                        "averageTemperature:" + wastewaterDO.getAverageTemperature() + "/n" +
                        "maximumTemperature:" + wastewaterDO.getMaximumTemperature() + "/n" +
                        "minimumTemperature:" + wastewaterDO.getMinimumTemperature() + "/n" +
                        "atmosphericPressure:" + wastewaterDO.getAtmosphericPressure() + "/n" +
                        "averageHumidity:" + wastewaterDO.getAverageHumidity() + "/n" +
                        "totalRainfall:" + wastewaterDO.getTotalRainfall() + "/n" +
                        "averageVisibility" + wastewaterDO.getAverageVisibility() + "/n" +
                        "averageWindSpeed:" + wastewaterDO.getAverageWindSpeed() + "/n" +
                        "maximumWindSpeed:" + wastewaterDO.getMaximumWindSpeed());
        messages.add(chatMessage);
        return messages;
    }

    private String queryResult(String id, String taskId){
        QueryModelResultRequest request = new QueryModelResultRequest();
        request.setTaskId(taskId);
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        try {
            QueryModelResultResponse queryResultResp = client.queryModelResult(request);
            TaskStatus taskStatus = queryResultResp.getData().getTaskStatus();
            while (taskStatus == TaskStatus.PROCESSING) {
                if (stopWatch.getTotalTimeMillis() > 5000) {
                    log.error("正在生成报告中，请稍后再试试");
                }
                queryResultResp = client.queryModelResult(request);
                taskStatus = queryResultResp.getData().getTaskStatus();
                Thread.sleep(100);
            }
            if (taskStatus == TaskStatus.FAIL) {
                log.error("报告生成失败");
            }
            String resp = queryResultResp.getData().getChoices().get(0).getMessage().getContent().toString();
            stringRedisTemplate.opsForValue().set(String.format(WATER_DATA_REPORT, id), resp, 20, TimeUnit.SECONDS);
            stringRedisTemplate.delete(String.format(WATER_DATA_REPORT_TASK, id));
            return resp;
        } catch (Throwable ex) {
            log.error(ex.toString());
        } finally {
            stopWatch.stop();
        }
        return "";
    }


}
